package com.primeton.eos.oss.model.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.eos.foundation.database.DatabaseExt;
import com.primeton.eos.api.springboot.EOS8ApplicationContext;
import com.primeton.eos.oss.model.dao.AfcEmployeeDao;
import com.primeton.eos.oss.model.dao.AfcOrgDao;
import com.primeton.eos.oss.model.dao.AfcROrgPositionDao;
import com.primeton.eos.oss.model.dao.AfcRPartyRoleDao;
import com.primeton.eos.oss.model.dao.AfcUserDao;
import com.primeton.eos.oss.model.dto.SynDataObjcetDto;
import com.primeton.eos.oss.model.dto.SynOrgDto;
import com.primeton.eos.oss.model.dto.SynUserDto;
import com.primeton.eos.oss.model.newdataset.AfcEmployee;
import com.primeton.eos.oss.model.newdataset.AfcOrg;
import com.primeton.eos.oss.model.newdataset.AfcROrgPosition;
import com.primeton.eos.oss.model.newdataset.AfcRPartyRole;
import com.primeton.eos.oss.model.newdataset.AfcUser;
import com.primeton.eos.oss.model.newdataset.CrecSysOrganization;
import com.primeton.eos.oss.model.newdataset.CrecSysOrganizationHis;
import com.primeton.eos.oss.model.newdataset.impl.AfcEmployeeImpl;
import com.primeton.eos.oss.model.newdataset.impl.AfcOrgImpl;
import com.primeton.eos.oss.model.newdataset.impl.AfcROrgPositionImpl;
import com.primeton.eos.oss.model.newdataset.impl.AfcRPartyRoleImpl;
import com.primeton.eos.oss.model.newdataset.impl.AfcUserImpl;
import com.primeton.eos.oss.model.result.BusinessException;
import com.primeton.eos.oss.model.result.RetCode;
import com.primeton.eos.oss.model.utils.Sm4Utils;
import com.primeton.gocom.afcenter.common.constants.CommonConstants;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ThirdSynDataService {

	@Autowired
	AfcEmployeeDao afcEmployeeDao;
	
	@Autowired
	AfcUserDao afcUserDao;

	@Autowired
	AfcROrgPositionDao afcROrgPositionDao;

	@Autowired
	AfcRPartyRoleDao afcRPartyRoleDao;

	@Autowired
	AfcOrgDao afcOrgDao;

	@Autowired
	private BCryptPasswordEncoder bCryptPasswordEncoder;

	@Autowired
	MdmSynDealService mdmSynDealService;

	private static final Logger log = LoggerFactory.getLogger(ThirdSynDataService.class);

	// 请求发起地址
	public final static String baseUrl = EOS8ApplicationContext.INSTANCE.getProperty("syn_data_base_url");
//	public final static String baseUrl = "http://10.2.38.90:9095";
	// 默认角色
	public final static String defaultRoleId = EOS8ApplicationContext.INSTANCE.getProperty("syn_default_role_id");
	// 默认机构主键
	public final static String defaultOrgId = EOS8ApplicationContext.INSTANCE.getProperty("syn_default_org_id");
	// 默认岗位主键
	public final static String defaultPositionId = EOS8ApplicationContext.INSTANCE
			.getProperty("syn_default_position_id");
	// 默认参与者ID
	public final static String defaultPartyId = EOS8ApplicationContext.INSTANCE.getProperty("syn_default_patrty_id");

	public final static String client_id = EOS8ApplicationContext.INSTANCE.getProperty("client_id");

	public static final String client_secret = EOS8ApplicationContext.INSTANCE.getProperty("client_secret");

	public static final String integration_key = EOS8ApplicationContext.INSTANCE.getProperty("integration_key");

	public static final String consumer_code = EOS8ApplicationContext.INSTANCE.getProperty("consumer_code");

	public static final String run_count = EOS8ApplicationContext.INSTANCE.getProperty("run_count");

//	// 默认角色
//	public final static String defaultRoleId = "9";
//	// 默认机构主键
//	public final static String defaultOrgId = "1";
//	// 默认岗位主键
//	public final static String defaultPositionId = "4";
//	// 默认参与者ID
//	public final static String defaultPartyId = "1";
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void loadUser() throws IOException {

		// 获取token'
		// 根据数据处理对应业务
		// TODO 当业务处理异常的时候，需要返回异常处理逻辑

		String tokenId = null;
		Map map = null;
		try {
			if(StringUtils.isBlank(tokenId)) {
				tokenId = getTokenId();
			}
			lodaDatas(tokenId);
		} catch (Exception ex) {
			log.error("处理异常:" + ex);
		} finally {
			// 退出TOKEN
			try {
				loginOutToken(tokenId);
			} catch (Exception ex) {

			}
		}

	}

	public void lodaDatas(String tokenId) throws Exception {
		// 获取token'
		// 根据数据处理对应业务
		// TODO 当业务处理异常的时候，需要返回异常处理逻辑
		String message = null;
		Map map = null;
		try {
			// 获取数据
			if (StringUtils.isBlank(tokenId)) {
				return;
			}
			
			for(int count=0;count<=Integer.valueOf(run_count);count++) {
				map = querDatas(tokenId);
				if (null == map) {
					return;
				}
				if ("{}".equals(map.get("data").toString())) {
					return;
				}
				
				pullFinsh(map, tokenId, dealBuessiness(map, null));
				
			}
			
			// 完成接口
		} catch (Exception ex) {
			log.info("lodaDatas run is error:" + ex);

		}
	}

	private void loginOutToken(String tokenId) throws Exception {
		StringBuffer sb = new StringBuffer();
		String url = baseUrl + "/cn.crec.group.sso.integration.api.jsonV2";
		Map<String, String> headersMap = headerMap();
		JSONObject requestObject = new JSONObject();
		requestObject.put("tokenId", tokenId);
		requestObject.put("timestamp", System.currentTimeMillis());
		sb.append(url).append("?method=logout").append("&request=" + requestObject.toJSONString());
		HttpResponse response = HttpUtil.createGet(sb.toString()).addHeaders(headersMap).execute();
		if (!response.isOk()) {
			throw new IOException("Unexpected code " + response);
		}
		String body = response.body();
		if (!ObjectUtil.isNotNull(body)) {
			throw new IOException("返回报文为空");
		}
		Map resultMap = JSONUtil.toBean(body, Map.class);
		if (!"100000".equals(resultMap.get("code").toString())) {
			log.error("loginOutToken run error。"+(String) resultMap.get("message"));
			throw new IOException((String) resultMap.get("message"));
		}
	}

	private boolean pullFinsh(Map map, String tokenId, boolean success) throws Exception  {
		try {
			Map map1 = (Map) map.get("data");
//			if (!map1.get("effectOn").equals("CREATED")) {
//				return true;
//			}
			String id = (String) map1.get("id");
			String taskId = (String) map1.get("taskId");
			StringBuffer sb = new StringBuffer();
			String url = baseUrl + "/cn.crec.group.sso.integration.api.jsonV2";
			Map<String, String> headersMap = headerMap();
			JSONObject requestObject = new JSONObject();
			requestObject.put("tokenId", tokenId);
			requestObject.put("taskId", taskId);

			requestObject.put("success", success);
			requestObject.put("guid", id);
			
			if(!success) {
				requestObject.put("message", "同步异常");
			}

			requestObject.put("timestamp", System.currentTimeMillis());
			sb.append(url).append("?method=pullFinish").append("&request=" + requestObject.toJSONString());
			HttpResponse response = HttpUtil.createGet(sb.toString()).addHeaders(headersMap).execute();
			if (!response.isOk()) {
				throw new IOException("Unexpected code " + response);
			}
			String body = response.body();
			if (!ObjectUtil.isNotNull(body)) {
				throw new IOException("返回报文为空");
			}
			
			Map resultMap = JSONUtil.toBean(body, Map.class);
			if (!"100000".equals(resultMap.get("code").toString())) {
				log.error("pullFinsh run error." + (String) resultMap.get("message"));
				throw new IOException((String) resultMap.get("message"));
			}
			Map resutlMap = JSONUtil.toBean(map.get("data").toString(), Map.class);
			return (boolean) resutlMap.get("success");
		} catch (Exception ex) {
			log.error("pullFinsh run error",ex);
		}
		return true;

	}

	private boolean dealBuessiness(Map map, SynDataObjcetDto dto) {
		// 判断是用户还是组织同步类型
		try {

			Map map1 = (Map) map.get("data");
			String effectOn = (String) map1.get("effectOn");
			String objectType = (String) map1.get("objectType");
			if ("TARGET_ACCOUNT".equals(objectType)) {
				SynUserDto synUserDto = JSONUtil.toBean(map1.get("data").toString(), SynUserDto.class);
				//判断账号信息的组织信息是否有中文，如果有中文，则返回false。通知一体化平台，同步失败。
				if(containsChinese(synUserDto.get_organization())) {
					return false;
				}
				dto = buildDto("CREC_ACCOUNT", dto, map1.get("id").toString());
				synUserDto.setTaskDbId(map1.get("id").toString());
				dealUser(synUserDto, effectOn);
				mdmSynDealService.dealSynUser(effectOn, synUserDto, dto);

			} else if ("TARGET_ORGANIZATION".equals(objectType)) {
				SynOrgDto synOrgDto = JSONUtil.toBean(map1.get("data").toString(), SynOrgDto.class);
				dto = buildDto("crec_sys_organization", dto, map1.get("id").toString());
				dealOrg(map1, synOrgDto, effectOn);
				mdmSynDealService.dealSynOrgs(effectOn, synOrgDto, dto);
			}

		} catch (Exception ex) {
			log.error("dealBuessiness run error",ex);
			return false;
		}
		return true;
	}
	
	public static boolean containsChinese(String str) {
	    for (char c : str.toCharArray()) {
	        if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
	                || Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
	                || Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A) {
	            return true;
	        }
	    }
	    return false;
	}

	private SynDataObjcetDto buildDto(String objectType, SynDataObjcetDto dto, String id) throws Exception  {
		// 不为空，避免重复执行
		if (null != dto) {
			return dto;
		}
		Map map = new HashMap();
		map.put("dataType", objectType);
		Object[] datas = DatabaseExt.queryByNamedSql("mdm", "com.primeton.eos.oss.model.synDatasql.queryVersions", map);
		if (null == datas || datas.length == 0) {
			return null;
		}
		if (datas[0] instanceof SynDataObjcetDto) {
			SynDataObjcetDto dta = (SynDataObjcetDto) datas[0];
			dta.setId(id);
			return dta;
		}
		return null;
	}

	private void dealOrg(Map map, SynOrgDto synOrgDto, String effectOn) throws Exception  {
		// TODO 自动生成的方法存根
		String id = map.get("id").toString();
		Date date = DateUtil.date();
		AfcOrg dBafcOrg = afcOrgDao.getEntityByKey(AfcOrg.QNAME, id);
		if (dBafcOrg==null) {
			AfcOrg afcOrg = new AfcOrgImpl();
			afcOrg.setId(id);
			afcOrg.setCode(synOrgDto.getCode());
			afcOrg.setName(synOrgDto.getName());
			afcOrg.setTypes("bm");
			afcOrg.setOrgLevel(String.valueOf(synOrgDto.get_organization().split(",").length));
			if (StringUtils.isBlank(synOrgDto.get_parent())) {
				afcOrg.setParentId("");
			} else {
				afcOrg.setParentId(synOrgDto.get_parent());
			}
			afcOrg.setFullCodePath(synOrgDto.get_organization());
			afcOrg.setDimensionId("1");
			afcOrg.setDescription(synOrgDto.getDescription());
			afcOrg.setStatus(synOrgDto.getIsDisabled() ? "0" : "1");
			afcOrg.setCreateTime(date);
			afcOrg.setCreateUser("admin");
			afcOrg.setSortBy(BigDecimal.ZERO);
			afcOrg.setDimensionId("1");
			afcOrg.setTenantId("sys_tenant");
			afcOrgDao.insertEntity(afcOrg);
		} else if (dBafcOrg!=null) {
			if ("DELETED".equals(effectOn) || "DISABLED".equals(effectOn)) {
				AfcOrg afcOrg = new AfcOrgImpl();
				afcOrg.setId(id);
				afcOrg.setStatus("1");
				afcOrgDao.updateEntity(afcOrg);
			}else if ("ENABLED".equals(effectOn)) {
				AfcOrg afcOrg = new AfcOrgImpl();
				afcOrg.setId(id);
				afcOrg.setStatus("0");
				afcOrgDao.updateEntity(afcOrg);
			}else {
				AfcOrg afcOrg = new AfcOrgImpl();
				afcOrg.setId(id);
				afcOrg.setCode(synOrgDto.getCode());
				afcOrg.setName(synOrgDto.getName());
				afcOrg.setTypes("xt");
				afcOrg.setOrgLevel(String.valueOf(synOrgDto.get_organization().split(",").length));
				if (StringUtils.isBlank(synOrgDto.get_parent())) {
					afcOrg.setParentId("/");
				} else {
					afcOrg.setParentId(synOrgDto.get_parent());
				}
				afcOrg.setDimensionId("1");
				afcOrg.setFullCodePath(synOrgDto.get_organization());
				afcOrg.setDescription(synOrgDto.getDescription());
				afcOrg.setStatus(synOrgDto.getIsDisabled() ? "0" : "1");
				afcOrg.setUpdateTime(date);
				afcOrg.setUpdateUser("admin");
				afcOrg.setSortBy(BigDecimal.ZERO);
				afcOrg.setTenantId("sys_tenant");
				afcOrgDao.updateEntity(afcOrg);
			}
		}
	}

	/**
	 * 用户数据同步
	 * 
	 * @param synUserDto
	 * @param effectOn   包含CREATE（创建）、DISABLED（禁用）、
	 *                   DELETED（删除）、ENABLED（启用）、UPDATED（更新）
	 */
	private void dealUser(SynUserDto synUserDto, String effectOn) throws Exception  {
		// TODO 自动生成的方法存根
		String id = synUserDto.getTaskDbId();
		Date date = DateUtil.date();
		AfcEmployee dBafcEmployee = afcEmployeeDao.getEntityByKey(AfcEmployee.QNAME, id);
		if (dBafcEmployee==null) {
			AfcEmployee employee = new AfcEmployeeImpl();
			employee.setId(id);
			employee.setName(synUserDto.getUsername());
			employee.setCode(synUserDto.getUsername());
			employee.setGender(synUserDto.getSex());
			employee.setPEmail(synUserDto.getEmail());
			if (StringUtils.isNoneBlank(synUserDto.getMobile())) {
				employee.setPhoneNumber(Sm4Utils.decryptData(synUserDto.getMobile()));
			}
			employee.setTenantId("sys_tenant");
			employee.setCreateTime(date);
			employee.setCreateUser("admin");
			employee.setStatus(synUserDto.getIsLocked() ? "0" : "1");
			employee.setUpdateTime(date);
			afcEmployeeDao.insertEntity(employee);
			AfcUser user = new AfcUserImpl();
			user.setId(id);
			user.setEmployeeId(id);
			user.setCode(synUserDto.getUsername());
			user.setPassword(CommonConstants.INIT_PASSWORD);
			user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
			user.setIsAdmin("0");
			user.setStatus(synUserDto.getIsLocked() ? "0" : "1");
			user.setPasswordInit("1");
			user.setIsLock(synUserDto.getIsLocked() ? "1" : "0");
			user.setCreateTime(date);
			user.setTenantId("sys_tenant");
			user.setCreateUser("admin");
			user.setCreateTime(date);
			user.setUpdateTime(date);
			user.setLastLoginTime(date);
			afcUserDao.insertEntity(user);
			AfcROrgPosition afcROrgPosition = new AfcROrgPositionImpl();
			afcROrgPosition.setOrgId(synUserDto.get_organization());
			afcROrgPosition.setPositionId(defaultPositionId);
			afcROrgPosition.setEmployeeId(id);
			afcROrgPosition.setDependentType("1");
			afcROrgPositionDao.getPrimaryKey(afcROrgPosition);
			afcROrgPositionDao.insertEntity(afcROrgPosition);
			AfcRPartyRole afcRPartyRole = new AfcRPartyRoleImpl();
			afcRPartyRole.setPartyId(id);
			afcRPartyRole.setPartyType("user");
			afcRPartyRole.setRoleId(defaultRoleId);
			afcRPartyRole.setRoleType("platform");
			afcRPartyRoleDao.getPrimaryKey(afcRPartyRole);
			afcRPartyRoleDao.insertEntity(afcRPartyRole);
		} else if (dBafcEmployee!=null) {
			if ("DELETED".equals(effectOn) || "DISABLED".equals(effectOn)) {
				AfcUser user = new AfcUserImpl();
				user.setId(id);
				user.setStatus("0");
				user.setIsLock("1");
				user.setUpdateTime(date);
				afcUserDao.updateEntity(user);
				AfcEmployee employee = new AfcEmployeeImpl();
				employee.setId(id);
				employee.setStatus("0");
				employee.setUpdateTime(date);
				afcEmployeeDao.updateEntity(employee);
			}else if ("ENABLED".equals(effectOn)) {
				AfcUser user = new AfcUserImpl();
				user.setId(id);
				user.setStatus("1");
				user.setIsLock("0");
				user.setUpdateTime(date);
				afcUserDao.updateEntity(user);
				AfcEmployee employee = new AfcEmployeeImpl();
				employee.setId(id);
				employee.setStatus("1");
				employee.setUpdateTime(date);
				afcEmployeeDao.updateEntity(employee);
			}else {
				AfcUser user = new AfcUserImpl();
				user.setId(id);
				user.setEmployeeId(id);
				user.setStatus(synUserDto.getIsLocked() ? "0" : "1");
				user.setIsLock(synUserDto.getIsLocked() ? "1" : "0");
				user.setUpdateTime(date);
				afcUserDao.updateEntity(user);
				AfcEmployee employee = new AfcEmployeeImpl();
				employee.setId(id);
				employee.setGender(synUserDto.getSex());
				employee.setPEmail(synUserDto.getEmail());
				employee.setPhoneNumber(synUserDto.getMobile());
				employee.setStatus(synUserDto.getIsLocked() ? "0" : "1");
				employee.setUpdateTime(date);
				afcEmployeeDao.updateEntity(employee);
			}
		}
	}

	/**
	 * 获取
	 * 
	 * @return
	 * @throws Exception 
	 * @throws IOException
	 */
	public String getTokenId() throws Exception {
		StringBuffer sb = new StringBuffer();
		String url = baseUrl + "/cn.crec.group.sso.integration.api.jsonV2";
		Map<String, String> headersMap = headerMap();
		JSONObject requestObject = new JSONObject();
		requestObject.put("systemCode", client_id);
		requestObject.put("integrationKey", integration_key);
		requestObject.put("force", true);
		requestObject.put("timestamp", System.currentTimeMillis());
		sb.append(url).append("?method=login").append("&request=" + requestObject.toJSONString());
		HttpResponse response = HttpUtil.createGet(sb.toString()).addHeaders(headersMap).execute();
		if (!response.isOk()) {
			throw new Exception("Unexpected code " + response);
		}
		String body = response.body();
		if (!ObjectUtil.isNotNull(body)) {
			throw new Exception("返回报文为空");
		}
		
		Map map = JSONUtil.toBean(body, Map.class);
		if (!"100000".equals(map.get("code").toString())) {
			log.error("getTokenId run error." + (String) map.get("message"));
			throw new Exception((String) map.get("message"));
		}
		Map resutlMap = JSONUtil.toBean(map.get("data").toString(), Map.class);
		return (String) resutlMap.get("tokenId");
	}

	private Map querDatas(String tokenId) throws Exception {
		StringBuffer sb = new StringBuffer();
		String url = baseUrl + "/cn.crec.group.sso.integration.api.jsonV2";
		Map<String, String> headersMap = headerMap();
		JSONObject requestObject = new JSONObject();
		requestObject.put("tokenId", tokenId);
		requestObject.put("timestamp", System.currentTimeMillis());
		sb.append(url).append("?method=pullTask").append("&request=" + requestObject.toJSONString());
		HttpResponse response = HttpUtil.createGet(sb.toString()).addHeaders(headersMap).execute();
		if (!response.isOk()) {
			throw new IOException("Unexpected code " + response);
		}
		String body = response.body();
		if (!ObjectUtil.isNotNull(body)) {
			throw new IOException("返回报文为空");
		}
		log.info("querDatas返回数据结果：" + body);
		Map map = JSONUtil.toBean(body, Map.class);
		if (!"100000".equals(map.get("code").toString())) {
			log.error("querDatas run error."+(String) map.get("message"));
			throw new IOException((String) map.get("message"));
		}
		return map;
	}

	private Map headerMap() {
		Map<String, String> headerMap = new HashMap();
		headerMap.put("consumerCode", consumer_code);
		headerMap.put("operationCode", "cn.crec.group.sso.integration.api.jsonV2");
		headerMap.put("Accept", "application/json");
		headerMap.put("Content-Type", "application/json");
		return headerMap;
	}

	public void dealOrgStructure() {
		// TODO 自动生成的方法存根

	}

//	public static void main(String[] args) throws Exception {
//		try {
//
//			// 自定义秘钥
//			String key = "JLB6L6MJVIT5Z7IL";
//			String password = "123456";
//			// 解密
//			String str = "$2a$10$vX0KRoUf6r5yrFD2Mms/TOxIPwWlqZC0vRczwYwJYkUBNEZDDEc4";
//
//			SymmetricCrypto crypto = SmUtil.sm4(key.getBytes());
//			String s2 = crypto.encryptHex(password);
//			String s3 = crypto.decryptStr(str);
//
//			System.out.println(s2);
//			System.out.println(s3);
//
//			// 用工具类生成，此处使用随机秘钥，加解密需要使用同一个示例才可得到原始密码
//			SM4 sm4 = SmUtil.sm4();
//
//		} catch (Exception e) {
//			throw new RuntimeException(e);
//		}
//
//	}

}
